import os, sys, os.path
from PyQt4 import QtGui, QtCore
import prop_test_base



class PropTestWidget(QtGui.QWidget, prop_test_base.Ui_Form):
   def __init__(self, parent=None):
      QtGui.QWidget.__init__(self, parent)
      self.setupUi(self)      

      self.model = PropTestModel(None)      
      self.model.material = buildMaterial()
      self.treeView.setModel(self.model)
      #self.treeView.setRootIndex(self.model.indexOf(self.model.material))      
      
      self.custTreeView = PropTestTreeView(self.treeView.parent())
      self.custTreeView.setModel(self.model)

      self.custTreeView.setAlternatingRowColors(True)
      self.custTreeView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
      self.custTreeView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
      self.custTreeView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
      self.custTreeView.setRootIsDecorated(True)
      self.custTreeView.setEditTriggers(QtGui.QAbstractItemView.CurrentChanged|
                                    QtGui.QAbstractItemView.SelectedClicked)
      self.delegate = PropertyDelegate()
      self.custTreeView.setItemDelegate(self.delegate)
      #self.custTreeView.setRootIndex(self.model.indexOf(self.model.material))
      self.custTreeView.setIndentation(15)
      

   def setMaterial(self, material):
      """ Switch model over to a new material. """
      self.model.setMaterial(material)

class PropTestTreeView(QtGui.QTreeView):
   def __init__(self,parent):
      QtGui.QTreeView.__init__(self,parent)
   
   def drawBranches(self, painter, rect, index):
      opt = QtGui.QStyleOptionViewItem(self.viewOptions())
      
      item = index.internalPointer()

      # Draw background (separator or highlight)
      if item.isSeparator():
         painter.fillRect(rect, opt.palette.mid())
      elif self.selectionModel().isSelected(index):
         painter.fillRect(rect, opt.palette.brush(QtGui.QPalette.Highlight))
      
      #QtGui.QTreeView.drawBranches(self, painter, rect, index)
      if self.model().hasChildren(index):
         opt.state = opt.state | QtGui.QStyle.State_Children
         if self.isExpanded(index):
            opt.state = opt.state | QtGui.QStyle.State_Open
                     
         prim = QtCore.QRect(rect.left(), rect.top(), self.indentation(), rect.height())
         opt.rect = prim
         self.style().drawPrimitive(QtGui.QStyle.PE_IndicatorBranch, opt, painter, self)      
      
      
      # Draw line at bottom of non-separator branches
      if not item.isSeparator():
         saved_pen = painter.pen()      
         grid_color = opt.palette.mid().color()
         grid_pen = QtGui.QPen(grid_color)
         painter.setPen(grid_pen)
         painter.drawLine(rect.x(), rect.bottom(), rect.right(), rect.bottom())
         painter.setPen(saved_pen)
      
         

class PropTestModel(QtCore.QAbstractItemModel):
   def __init__(self, parent=None):
      QtCore.QAbstractItemModel.__init__(self, parent)
      self.material = None
      self.leaky_bucket = []       # Hold references to python objects so they stay alive

   def makeIndex(self, r, c, obj):
      self.leaky_bucket.append(obj)
      return self.createIndex(r,c,obj)
   
   def setMaterial(self, material):
      """ Set to a root node.  Reset the tree and data. """
      self.material = material
      self.leaky_bucket = []     # Clear out the bucket
      self.reset()               # Reset the model, triggers view reloads

   def isEditable(self, index):
      """ Return true if the index is editable. """
      if index.column() == 1 and index.internalPointer().hasEditor():
         return True 
      
   def flags(self, index):
      if not index.isValid():
         return QtCore.Qt.ItemIsEnabled
      
      ret_flags = QtCore.QAbstractItemModel.flags(self, index)
      if self.isEditable(index):
         ret_flags = ret_flags | QtCore.Qt.ItemIsEditable      
      return ret_flags

   def index(self, row, column, parentIdx):
      # If parent invalid, return highest level items
      if not parentIdx.isValid():
         if self.material:
            return self.makeIndex(row,column,self.material)
         else:
            return QtCore.QModelIndex()
      parent = parentIdx.internalPointer()
      
      return self.makeIndex(row, column, parent.getChild(row))
   

   def parent(self, childIdx):      
      # If invalid, or root, then return no parent
      if not childIdx.isValid():
         return QtCore.QModelIndex()

      child = childIdx.internalPointer()      
      assert child
      
      if self.material == child:
         return QtCore.QModelIndex()
      
      return self.indexOf(child.getParent())
   
   def indexOf(self, item):
      """ Return the index of item relative to parent. """
      if item == self.material:
         return self.createIndex(0, 0, self.material)
      
      parent = item.getParent()
      row = parent.indexOf(item)
      return self.makeIndex(row, 0, item)
   
   def rowCount(self, parentIdx):
      if not parentIdx.isValid():
         return 1               # Root node
      else:
         parent_node = parentIdx.internalPointer()
         return parent_node.getNChildren()   
   
   def columnCount(self, parent):
      # Just have 1 column for now
      return 2      
   
   def buddy(self, index):
      """ When trying to edit index, which index should be edited (my buddy.) """
      if index.column() == 0:
         return self.makeIndex(index.row(), 1, index.internalPointer())
      return index   # Default to being my buddy (column 1)

   def data(self, index, role):
      if not index.isValid():
         if role == QtCore.Qt.UserRole:
            return None
         else:
            return QtCore.QVariant()
         
      item = index.internalPointer()
      col = index.column()

      # Data
      if 0 == col:
         if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
            return QtCore.QVariant(item.getName())
         elif role == QtCore.Qt.UserRole:
            return item
      elif 1 == col:
         if role == QtCore.Qt.DisplayRole:
            return QtCore.QVariant(item.toString())
         elif role == QtCore.Qt.EditRole:
            return QtCore.QVariant(item.toString())   # Not used (delegate gets it direct)
         elif role == QtCore.Qt.DecorationRole:
            return item.decoration()
      
      # Formatting
      if QtCore.Qt.FontRole == role:
         print "Font"
      elif QtCore.Qt.BackgroundColorRole == role:
         print "Background"
         
      
      # Catch all
      return QtCore.QVariant()
   
   def headerData(self, col, orientation, role):
      if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
         headers = ["Property","Value"]         
         return QtCore.QVariant(str(headers[col]))
      return QtCore.QVariant()


   # ------------ Edit Interface ------------------- #
   #def setData(self, index, value, role):
   #   if not index.isValid():
   #      return False
   #   else:
   #      node = self.getContainer(index.internalId())
   #      if node and (role == QtCore.Qt.EditRole):
   #         osg2.setName(node, str(value.toString()))
   #         self.emit(QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index)
   #         self.emit(QtCore.SIGNAL("dataChanged(int)"), index.row())
   #         return True
   #   return False

class PropertyDelegate(QtGui.QItemDelegate):
   def __init__(self,parent=None):
      QtGui.QItemDelegate.__init__(self, parent)
   
   def createEditor(self, parent, option, index):
      """ Return widget for editing the given index. """
      assert index.isValid()
      item = index.internalPointer()
      if item.hasEditor():
         return item.createEditor(parent, option, index)
      else:
         return None
      
   def setEditorData(self, widget, index):
      item = index.internalPointer()
      item.setEditorData(widget,index)
   
   def setModelData(self, widget, model, index):
      item = index.internalPointer()
      item.setModelData(widget, model,index)
   
   def updateEditorGeometry(self, editor, option, index):
      editor.setGeometry(option.rect)
   
   def paint(self, painter, opt, index):
      print "delegate paint"
      item = None
      if index.isValid():
         item = index.internalPointer()
      option = QtGui.QStyleOptionViewItem(opt)    # Get copy of options

      # Separator and second column don't show selected
      if item.isSeparator() or index.column() == 1:
         option.state = option.state & ~QtGui.QStyle.State_Selected
      option.state = option.state & ~QtGui.QStyle.State_HasFocus
         
      # We are a separator, draw a background and disable selection
      if item.isSeparator():
         option.palette.setColor(QtGui.QPalette.Text, option.palette.color(QtGui.QPalette.BrightText))
         option.font.setBold(True)         
         
         #option.palette.setColor(QtGui.QPalette.Window, option.palette.color(QtGui.QPalette.Dark))
         bg = option.palette.mid()
         painter.fillRect(option.rect, bg)
      
      saved_pen = painter.pen()
      
      # Finish with default paint   
      QtGui.QItemDelegate.paint(self, painter, option, index)
      
      if not item.isSeparator():
         grid_color = option.palette.mid().color()
         grid_pen = QtGui.QPen(grid_color)
      
         painter.setPen(grid_pen)
         # Line at bottom of entry and line at right of entry
         painter.drawLine(option.rect.x(), option.rect.bottom(), option.rect.right(), option.rect.bottom())         
         painter.drawLine(option.rect.right(), option.rect.y(), option.rect.right(), option.rect.bottom())
      painter.setPen(saved_pen)
      

class IProperty(object):
   def __init__(self):
      self.name = "<noname>"
      self.children = []
      
   def getName(self):
      return self.name
   def toString(self):
      return "str"
   def value(self):
      return self.toString()
   def decoration(self):
      return QtCore.QVariant()
   
   def hasEditor(self,index):
      return False
   def isSeparator(self):
      return False
   
   def getChild(self, index):
      return self.children[index]
   def getNChildren(self):
      return len(self.children)
   def indexOf(self, item):
      return self.children.index(item)

   def getParent(self):
      return None


class MaterialProp(IProperty):
   def __init__(self, name):
      super(MaterialProp,self).__init__()      
      self.name = name      
   
   def toString(self):
      return "Mat: %s"%self.name
   def value(self):
      return "no_value"
   def hasEditor(self):
      return False
      
   def getParent(self):
      return None
   
class ChunkProp(IProperty):
   def __init__(self, name, mat):
      super(ChunkProp,self).__init__()
      self.name = name
      self.material = mat      

   def toString(self):
      return "Chunk: %s"%self.name
   def value(self):
      return "no_value"
   def hasEditor(self):
      return False
   def isSeparator(self):
      return True
      
   def getParent(self):
      return self.material
   

class StringProperty(IProperty):
   def __init__(self, name, chunk):
      super(StringProperty,self).__init__()
      self.name = name
      self.chunk = chunk
      self.value = "string"

   def toString(self):
      return self.value
   def value(self):
      return self.value
   def hasEditor(self):
      return False
      
   def getParent(self):
      return self.chunk


class FloatProperty(IProperty):
   def __init__(self, name, chunk):
      super(FloatProperty,self).__init__()
      self.name = name
      self.chunk = chunk   
      self.value = 0.0

   def toString(self):
      return str(self.value)
   def value(self):
      return self.value
   def hasEditor(self):
      return True
   def createEditor(self, parent, option, index):
      editor = QtGui.QSpinBox(parent)
      editor.setMinimum(0)
      editor.setMaximum(100)
      return editor
   def setEditorData(self, widget, index):
      widget.setValue(self.value)
   def setModelData(self, widget, model, index):
      self.value = widget.value()      
      
   def getParent(self):
      return self.chunk


# BlendChunk support

#osg2.BlendChunk

#GlEnumProperty("srcFactor","getSrcFactor","setSrcFactor",
#    ["GL_ZERO","GL_ONE","GL_DST_COLOR","GL_SRC_COLOR","GL_ONE_MINUS_DST_COLOR",
#     "GL_ONE_MINUS_SRC_COLOR","GL_SRC_ALPHA","GL_ONE_MINUS_SRC_ALPHA"])
 
#Color4fProperty("color","getColor","setColor")
 
#RealProperty("alphaValue", "getAlphaValue","setAlphaValue", (0.0,1.0))


def buildMaterial():
   mat = MaterialProp("myMat")
   c1 = ChunkProp("Chunk1",mat)
   c2 = ChunkProp("Chunk2",mat)
   c3 = ChunkProp("Chunk3",mat)      
   c4 = ChunkProp("Chunk4",mat)
   
   for c in [c1,c2,c3,c4]:
      mat.children.append(c)
      c.children.append(StringProperty("prop1",c))
      c.children.append(FloatProperty("prop2",c))      
   
   return mat 
   


if __name__ == "__main__":
   app = QtGui.QApplication(sys.argv)
   gui = PropTestWidget()   
   gui.show()
   sys.exit(app.exec_())
